package oneD.dynamics;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

import ptolemy.plot.Plot;

public class Plot1D extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private JTextField dtTf;// = new JTextField("");
	private JTextField nTf;// = new JTextField("");
	private JTextField nodeTf;// = new JTextField("");
	private JCheckBox showGridCb = new JCheckBox("Show grid");
	private JCheckBox xCb = new JCheckBox("x");
	private JCheckBox yCb = new JCheckBox("y");
	private JCheckBox zCb = new JCheckBox("z");
	private JCheckBox disCb = new JCheckBox("displacement");
	private JCheckBox velCb = new JCheckBox("velocity");
	private JCheckBox accCb = new JCheckBox("acceleration");
	private JRadioButton resRb = new JRadioButton("response diagram");
	private JRadioButton phaRb = new JRadioButton("phase diagram");
	private Plot plot = new Plot();

	private DynamicStructure struct_;

	public Plot1D(DynamicStructure struct) {
		setTitle("Dynamic response plot");
		setLayout(new BorderLayout(5, 5));
		nodeTf = new JTextField("0,1");
		dtTf = new JTextField("0");
		nTf = new JTextField("0");
		xCb.setSelected(true);
		yCb.setSelected(true);
		disCb.setSelected(true);
		resRb.setSelected(true);
		showGridCb.setSelected(true);

		add(createWestPanel(), BorderLayout.WEST);
		add(this.plot, BorderLayout.CENTER);
		add(createSouthPanel(), BorderLayout.SOUTH);

		Toolkit tk = Toolkit.getDefaultToolkit();
		int xSize = ((int) tk.getScreenSize().getWidth());
		int ySize = ((int) tk.getScreenSize().getHeight());
		setSize(xSize - 100, ySize);

		this.struct_ = struct;
	}

	public void setDt(double dt) {
		this.dtTf.setText(Double.toString(dt));
	}

	public void setN(int n) {
		this.nTf.setText(Integer.toString(n));
	}

	private JPanel createWestPanel() {
		JPanel wp = new JPanel(new BorderLayout());
		wp.add(createInfoPanel(), BorderLayout.NORTH);
		wp.add(createSelectionPanel(), BorderLayout.CENTER);
		wp.add(createSettingsPanel(), BorderLayout.SOUTH);
		return wp;
	}

	private JPanel createInfoPanel() {
		JPanel sp = new JPanel(new BorderLayout(5, 5));
		JPanel p1 = new JPanel(new GridLayout(2, 1, 0, 2));
		JPanel p2 = new JPanel(new GridLayout(2, 1, 0, 2));

		p1.add(new JLabel("dt = ", JLabel.RIGHT));
		p1.add(new JLabel("n = ", JLabel.RIGHT));

		p2.add(this.dtTf);
		p2.add(this.nTf);

		sp.setBorder(BorderFactory.createTitledBorder("Info"));
		sp.add(p1, BorderLayout.WEST);
		sp.add(p2, BorderLayout.CENTER);
		return sp;
	}

	private JPanel createSelectionPanel() {
		JPanel sp = new JPanel(new BorderLayout(5, 5));
		JPanel p = new JPanel(new GridLayout(2, 1, 0, 2));
		p.add(resRb);
		p.add(phaRb);

		sp.setBorder(BorderFactory.createTitledBorder("Diagram"));
		sp.add(p, BorderLayout.CENTER);

		return sp;
	}

	private JPanel createSettingsPanel() {
		JPanel sp = new JPanel(new BorderLayout(5, 5));
		JPanel p1 = new JPanel(new GridLayout(1, 1, 0, 2));
		JPanel p2 = new JPanel(new GridLayout(1, 1, 0, 2));
		JPanel p3 = new JPanel(new GridLayout(7, 1, 0, 2));

		p1.add(new JLabel("node:", JLabel.RIGHT));

		p2.add(this.nodeTf);

		p3.add(this.xCb);
		p3.add(this.yCb);
		p3.add(this.zCb);
		p3.add(this.disCb);
		p3.add(this.velCb);
		p3.add(this.accCb);
		p3.add(this.showGridCb);

		sp.setBorder(BorderFactory.createTitledBorder("Settings"));
		sp.add(p1, BorderLayout.WEST);
		sp.add(p2, BorderLayout.CENTER);
		sp.add(p3, BorderLayout.SOUTH);

		return sp;
	}

	private JPanel createSouthPanel() {
		JPanel p = new JPanel(new FlowLayout(FlowLayout.RIGHT));
		p.add(createPlotButton());
		p.add(createExitButton());
		return p;
	}

	private JButton createExitButton() {
		JButton b = new JButton("Exit");

		b.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		return b;
	}

	private JButton createPlotButton() {
		JButton b = new JButton("Plot");

		b.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				plot();
			}
		});
		return b;
	}

	private void plot() {
		try {
			this.plot.clear(true);
			this.plot.setGrid(this.showGridCb.isSelected());
			this.plot.setXLabel("time (s)");

			Integer[] nodeIdSet = this.getNodeIdSet();
			Integer[] axisSet = this.getAxisSet();

			if (this.resRb.isSelected()) {
				Integer[] typeSet = this.getTypeSet();

				for (int i = 0; i < nodeIdSet.length; i++)
					for (int j = 0; j < typeSet.length; j++)
						for (int k = 0; k < axisSet.length; k++) {
							int datasetId = i * typeSet.length * axisSet.length
									+ j * axisSet.length + k;
							String legend = "u" + i + getAxisName(axisSet[k])
									+ getTypeName(typeSet[j]);
							this.plot.addLegend(datasetId, legend);
							for (int l = 0; l < this.struct_.getNumberOfStep(); l++) {
								double x = l
										* this.struct_.getTimeStepForPlot();
								double y = this.struct_.getNode(nodeIdSet[i])
										.get(l, typeSet[j]).get(axisSet[k]);
								this.plot.addPoint(datasetId, x, y, true);
							}
						}
			}
			if (this.phaRb.isSelected()) {
				for (int i = 0; i < nodeIdSet.length; i++)
					for (int k = 0; k < axisSet.length; k++) {
						int datasetId = i * axisSet.length + k;
						String legend = "u" + i + getAxisName(axisSet[k])
								+ "-u" + i + getAxisName(axisSet[k]) + "d";
						this.plot.addLegend(datasetId, legend);
						for (int l = 0; l < this.struct_.getNumberOfStep(); l++) {
							double x = this.struct_.getNode(nodeIdSet[i])
									.get(l, 0).get(axisSet[k]);
							double y = this.struct_.getNode(nodeIdSet[i])
									.get(l, 1).get(axisSet[k]);
							this.plot.addPoint(datasetId, x, y, true);
						}
					}
			}
			this.plot.repaint();
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, e.getMessage());
		}
	}

	private Integer[] getAxisSet() {
		ArrayList<Integer> list = new ArrayList<Integer>();
		if (this.xCb.isSelected())
			list.add(0);
		if (this.yCb.isSelected())
			list.add(1);
		if (this.zCb.isSelected())
			list.add(2);
		Integer[] a = list.toArray(new Integer[list.size()]);
		return a;
	}

	private Integer[] getTypeSet() {
		ArrayList<Integer> list = new ArrayList<Integer>();
		if (this.disCb.isSelected())
			list.add(0);
		if (this.velCb.isSelected())
			list.add(1);
		if (this.accCb.isSelected())
			list.add(2);
		Integer[] a = list.toArray(new Integer[list.size()]);
		return a;
	}

	private Integer[] getNodeIdSet() {
		ArrayList<Integer> list = new ArrayList<Integer>();
		String s = this.nodeTf.getText();
		StringTokenizer st = new StringTokenizer(s, ",");
		while (st.hasMoreTokens()) {
			String val = st.nextToken();
			list.add(Integer.parseInt(val));
		}
		Integer[] a = list.toArray(new Integer[list.size()]);
		return a;
	}

	private String getAxisName(int axisNumber) {
		return axisNumber == 0 ? "x" : axisNumber == 1 ? "y" : "z";
	}

	private String getTypeName(int typeNumber) {
		return typeNumber == 0 ? "" : typeNumber == 1 ? "d" : "dd";
	}

}
